/*
 *  inputbox.c -- implements the input box
 *
 *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "dialog.h"

char dialog_input_result[MAX_LEN + 1];

/*
 *  Print the termination buttons
 */
static void print_buttons(WINDOW* dialog, int height, int width, int selected)
{
	int x = width / 2 - 11;
	int y = height - 2;

	print_button(dialog, gettext("  Ok  "), y, x, selected == 0);
	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);

	wmove(dialog, y, x + 1 + 14 * selected);
	wrefresh(dialog);
}

/*
 * Display a dialog box for inputing a string
 */
int dialog_inputbox(const char* title, const char* prompt, int height, int width,
                    const char* init)
{
	int i, x, y, box_y, box_x, box_width;
	int input_x = 0, key = 0, button = -1;
	int show_x, len, pos;
	char* instr = dialog_input_result;
	WINDOW* dialog;

	if(!init)
		instr[0] = '\0';
	else
		strcpy(instr, init);

do_resize:

	if(getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
		return -ERRDISPLAYTOOSMALL;

	if(getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
		return -ERRDISPLAYTOOSMALL;

	/* center dialog box on screen */
	x = (getmaxx(stdscr) - width) / 2;
	y = (getmaxy(stdscr) - height) / 2;

	draw_shadow(stdscr, y, x, height, width);

	dialog = newwin(height, width, y, x);
	keypad(dialog, TRUE);

	draw_box(dialog, 0, 0, height, width,
	         dlg.dialog.atr, dlg.border.atr);
	wattrset(dialog, dlg.border.atr);
	mvwaddch(dialog, height - 3, 0, ACS_LTEE);

	for(i = 0; i < width - 2; i++)
		waddch(dialog, ACS_HLINE);

	wattrset(dialog, dlg.dialog.atr);
	waddch(dialog, ACS_RTEE);

	print_title(dialog, title, width);

	wattrset(dialog, dlg.dialog.atr);
	print_autowrap(dialog, prompt, width - 2, 1, 3);

	/* Draw the input field box */
	box_width = width - 6;
	getyx(dialog, y, x);
	box_y = y + 2;
	box_x = (width - box_width) / 2;
	draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
	         dlg.dialog.atr, dlg.border.atr);

	print_buttons(dialog, height, width, 0);

	/* Set up the initial value */
	wmove(dialog, box_y, box_x);
	wattrset(dialog, dlg.inputbox.atr);

	len = strlen(instr);
	pos = len;

	if(len >= box_width) {
		show_x = len - box_width + 1;
		input_x = box_width - 1;

		for(i = 0; i < box_width - 1; i++)
			waddch(dialog, instr[show_x + i]);
	} else {
		show_x = 0;
		input_x = len;
		waddstr(dialog, instr);
	}

	wmove(dialog, box_y, box_x + input_x);

	wrefresh(dialog);

	while(key != KEY_ESC) {
		key = wgetch(dialog);

		if(button == -1) {	/* Input box selected */
			switch(key) {
				case TAB:
				case KEY_UP:
				case KEY_DOWN:
					break;

				case KEY_BACKSPACE:
				case 127:
					if(pos) {
						wattrset(dialog, dlg.inputbox.atr);

						if(input_x == 0) {
							show_x--;
						} else
							input_x--;

						if(pos < len) {
							for(i = pos - 1; i < len; i++) {
								instr[i] = instr[i + 1];
							}
						}

						pos--;
						len--;
						instr[len] = '\0';
						wmove(dialog, box_y, box_x);

						for(i = 0; i < box_width; i++) {
							if(!instr[show_x + i]) {
								waddch(dialog, ' ');
								break;
							}

							waddch(dialog, instr[show_x + i]);
						}

						wmove(dialog, box_y, input_x + box_x);
						wrefresh(dialog);
					}

					continue;

				case KEY_LEFT:
					if(pos > 0) {
						if(input_x > 0) {
							wmove(dialog, box_y, --input_x + box_x);
						} else if(input_x == 0) {
							show_x--;
							wmove(dialog, box_y, box_x);

							for(i = 0; i < box_width; i++) {
								if(!instr[show_x + i]) {
									waddch(dialog, ' ');
									break;
								}

								waddch(dialog, instr[show_x + i]);
							}

							wmove(dialog, box_y, box_x);
						}

						pos--;
					}

					continue;

				case KEY_RIGHT:
					if(pos < len) {
						if(input_x < box_width - 1) {
							wmove(dialog, box_y, ++input_x + box_x);
						} else if(input_x == box_width - 1) {
							show_x++;
							wmove(dialog, box_y, box_x);

							for(i = 0; i < box_width; i++) {
								if(!instr[show_x + i]) {
									waddch(dialog, ' ');
									break;
								}

								waddch(dialog, instr[show_x + i]);
							}

							wmove(dialog, box_y, input_x + box_x);
						}

						pos++;
					}

					continue;

				default:
					if(key < 0x100 && isprint(key)) {
						if(len < MAX_LEN) {
							wattrset(dialog, dlg.inputbox.atr);

							if(pos < len) {
								for(i = len; i > pos; i--)
									instr[i] = instr[i - 1];

								instr[pos] = key;
							} else {
								instr[len] = key;
							}

							pos++;
							len++;
							instr[len] = '\0';

							if(input_x == box_width - 1) {
								show_x++;
							} else {
								input_x++;
							}

							wmove(dialog, box_y, box_x);

							for(i = 0; i < box_width; i++) {
								if(!instr[show_x + i]) {
									waddch(dialog, ' ');
									break;
								}

								waddch(dialog, instr[show_x + i]);
							}

							wmove(dialog, box_y, input_x + box_x);
							wrefresh(dialog);
						} else
							flash();	/* Alarm user about overflow */

						continue;
					}
			}
		}

		switch(key) {
			case 'O':
			case 'o':
				delwin(dialog);
				return 0;

			case 'H':
			case 'h':
				delwin(dialog);
				return 1;

			case KEY_UP:
			case KEY_LEFT:
				switch(button) {
					case -1:
						button = 1;	/* Indicates "Help" button is selected */
						print_buttons(dialog, height, width, 1);
						break;

					case 0:
						button = -1;	/* Indicates input box is selected */
						print_buttons(dialog, height, width, 0);
						wmove(dialog, box_y, box_x + input_x);
						wrefresh(dialog);
						break;

					case 1:
						button = 0;	/* Indicates "OK" button is selected */
						print_buttons(dialog, height, width, 0);
						break;
				}

				break;

			case TAB:
			case KEY_DOWN:
			case KEY_RIGHT:
				switch(button) {
					case -1:
						button = 0;	/* Indicates "OK" button is selected */
						print_buttons(dialog, height, width, 0);
						break;

					case 0:
						button = 1;	/* Indicates "Help" button is selected */
						print_buttons(dialog, height, width, 1);
						break;

					case 1:
						button = -1;	/* Indicates input box is selected */
						print_buttons(dialog, height, width, 0);
						wmove(dialog, box_y, box_x + input_x);
						wrefresh(dialog);
						break;
				}

				break;

			case ' ':
			case '\n':
				delwin(dialog);
				return (button == -1 ? 0 : button);

			case 'X':
			case 'x':
				key = KEY_ESC;
				break;

			case KEY_ESC:
				key = on_key_esc(dialog);
				break;

			case KEY_RESIZE:
				delwin(dialog);
				on_key_resize();
				goto do_resize;
		}
	}

	delwin(dialog);
	return KEY_ESC;		/* ESC pressed */
}
